﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using NHunspell;


namespace CortexMod
{
    class Cortex
    {
        int[][] matrizincidencia;
        int frecuenciaTotalpalabras=0;
        int[] indiceTabla;

        float votoEntropia = 0;
        float votoFrecuencia = 0;


        int[] p;
        float[] entropia;

        int[] rareza;
        float[] frecuenciaRareza;

        String[] arregloDeFrasesOriginal = null;
        String[] arregloDeFrasesCortex = null;
        char[] delimiterChars = { '.'/*, '\t','\n'*/ };
        String[] palabras = 
            {" el "," El "," la "," La "," los "," Los "," las "," Las "," un "," Un "," una "," Una "," unos "," Unos "," unas "," Unas ", //articulos
            " yo "," Yo ", " tú "," Tú ", " vos "," Vos ", " Usted "," usted "," ello "," Ello "," nosotros "," Nosotros "," nosotras "," Nosotras "," ustedes "," Ustedes "," vosotros "," Vosotros "," vosotras "," Vosotras "," ellos "," Ellos "," ellas "," Ellas "," un "," Un "," unos "," Unos "," unas "," Unas "," una "," Una ", //pronombres
            " ser "," estar "," tener "," deber ", //verbos funcionales
            " es decir "," entonces "," a lo mejor "}; //expresiones
              

        public Cortex(String texto)
        {
           
            //deberia filtrase primero por numeros antes de segmentarse porque algunos numeros tienen punto, es decir 1.200,35 habitantes

            texto = texto.Replace("\n", " ");
            texto = texto.Replace("\n\n", "");
            texto = texto.Replace("\r\n", "");
            texto = texto.Replace("\n \n \n", "");
            texto = texto.Replace("\n\n\n", "");
            texto = texto.Replace("\r", " ");
            texto = texto.Replace("\t\t", "\t");
            texto = texto.Replace(" \t", "\t");
            texto = texto.Replace("  ", " ");
            texto = texto.Replace("   ", " ");
            texto = texto.Replace("    ", " ");
            texto = texto.Replace("/", " ");
            texto = texto.Replace("- ", "");
            texto = texto.Replace(" - ", "");
            texto = texto.Replace("!", "");
            texto = texto.Replace(":", "");

            texto = texto.Replace("...\n", ".");
            
            texto = texto.Replace("...", " ");
            
            //texto = texto.Replace("..", ".");
            
            
            texto = texto.Replace(". ", ".");
            texto = texto.Replace(".  ", ".");
            texto = texto.Replace(".   ", ".");
            texto = texto.Replace(".\n", ".");
            texto = texto.Replace(".\t", ".");
            
 
            
            arregloDeFrasesOriginal = texto.Split(delimiterChars);
            arregloDeFrasesCortex = texto.Split(delimiterChars);
            
            
            //segmentar();
            filtrarParentesis();
            filtrarNumeros();
            filtrarPalabras();
            filtrarLematizar();
            filtrarNormalizar();
            filtrarVectorizacion();
            calculosIndicesParaMetricasCortex();
            entropiaCortex();
            frecuenciaXrarezaCortex();
            normalizacionMetricas();
            algoritmoDecision();
        }

        public void segmentar()
        {
            arregloDeFrasesCortex = arregloDeFrasesOriginal;
        }

        public void filtrarParentesis()
        {
            
            String parentesisAbierto = "(";
            String parentesisCerrado = ")";
            
            for(int i=0;i<arregloDeFrasesCortex.Length;i++)
            {
                bool bandera = true;

                while (bandera)
                {

                    int inicio = arregloDeFrasesCortex[i].IndexOf(parentesisAbierto);
                    int final = arregloDeFrasesCortex[i].IndexOf(parentesisCerrado);


                    if (inicio == -1 && final == -1)
                    {
                        bandera = false;
                    }
                    else
                    if (inicio != -1 && final == -1)
                    {
                        arregloDeFrasesCortex[i] = arregloDeFrasesCortex[i].Replace(arregloDeFrasesCortex[i].Substring(inicio, 1), "");
                    }
                    else
                    if (inicio == -1 && final != -1)
                    {
                        arregloDeFrasesCortex[i] = arregloDeFrasesCortex[i].Replace(arregloDeFrasesCortex[i].Substring(final, 1), "");
                    }
                    else
                    if (inicio != -1 && final != -1 && inicio < final)
                    {
                        arregloDeFrasesCortex[i] = arregloDeFrasesCortex[i].Replace(arregloDeFrasesCortex[i].Substring(inicio, final - inicio + 1), "");
                    }
                    else
                    if (inicio != -1 && final != -1 && inicio > final)
                    {

                         arregloDeFrasesCortex[i] = arregloDeFrasesCortex[i].Replace(arregloDeFrasesCortex[i].Substring(inicio, 1), "");
                         arregloDeFrasesCortex[i] = arregloDeFrasesCortex[i].Replace(arregloDeFrasesCortex[i].Substring(final, 1), "");

                    }

                }
            }
        
        }

        public void filtrarNumeros()
        {
            //splitear la frase[i] y verificar si tiene numeros para eliminarlos
            
            char[] separador={' '};
            String[] numeros = null;

            for (int i = 0; i < arregloDeFrasesCortex.Length; i++)
            {
                numeros =  arregloDeFrasesCortex[i].Split(separador);

                for (int j = 0; j < numeros.Length; j++)
                {
                    try
                    {
                        int.Parse(numeros[j]);
                        arregloDeFrasesCortex[i] = arregloDeFrasesCortex[i].Replace(numeros[j], "");
         
                    }
                    catch
                    { 
                    
                    }
                }

            }
        }

        public void filtrarPalabras()
        {
            for (int i = 0; i < arregloDeFrasesCortex.Length; i++)
            {

                for (int j = 0; j < palabras.Length; j++)
                {
                    arregloDeFrasesCortex[i] = arregloDeFrasesCortex[i].ToLower().Replace(palabras[j].ToLower(), " ");
                    
                }

                arregloDeFrasesCortex[i] = arregloDeFrasesCortex[i].Replace(". ", ".");
                arregloDeFrasesCortex[i] = arregloDeFrasesCortex[i].Replace(".  ", ".");
            
            }
        }


        public void filtrarLematizar()
        {

            using (Hunspell hunspell = new Hunspell("CortexModule/Hunspell/es_ES.aff", "CortexModule/Hunspell/es_ES.dic"))
            {

                for (int i = 0; i < arregloDeFrasesCortex.Length; i++)
                {
                    palabras = arregloDeFrasesCortex[i].Split(' ');

                    for (int j = 0; j < palabras.Length; j++)
                    {
                        //Console.WriteLine(palabras[j]);
                        List<string> stems = hunspell.Stem(palabras[j]);
                        
                        /*
                        foreach (string stem in stems)
                        {
                            
                            Console.WriteLine("Word Stem is: " + stem);
                        }*/

                        if (stems.Count > 2)
                        {
                            arregloDeFrasesCortex[i] = arregloDeFrasesCortex[i].Replace(palabras[j], stems.ElementAt(1));
                            //Console.WriteLine("considerar: " + stems.ElementAt(1));
                            //Console.WriteLine("\n");
                        }
                    }


                    //Console.WriteLine("cambio-- \n");
                }

                
            }
        }

        public void filtrarNormalizar()
        {
            List<string> listadoPalabras = new List<string>();
            List<string> listadoPalabrasIndice = new List<string>();

            using (Hunspell hunspell = new Hunspell("CortexModule/Hunspell/es_ES.aff", "CortexModule/Hunspell/es_ES.dic"))
            {
                for (int i = 0; i < arregloDeFrasesCortex.Length; i++)
                {
                    palabras = arregloDeFrasesCortex[i].Split(' ');

                    for (int j = 0; j < palabras.Length; j++)
                    {

                        List<string> suggestions = hunspell.Suggest(palabras[j]);
                      //  Console.WriteLine(palabras[j]+" hay " + suggestions.Count.ToString() + " sugerencias");

                        /*foreach (string suggestion in suggestions)
                        {
                            Console.WriteLine("Sugerencia: " + suggestion);
                        }*/
                    }
                }
            }
        }

        public void filtrarVectorizacion()
        {

            Dictionary<string,int> vector = new Dictionary<string, int>();
            int tamañoDiccionario = 0;
            
            for (int i = 0; i < arregloDeFrasesCortex.Length; i++)
            {
                palabras = arregloDeFrasesCortex[i].Split(' ');

                for (int j = 0; j < palabras.Length; j++)
                {
                    try
                    {
                        vector.Add(palabras[j], 1);
                    }
                    catch
                    {
                        vector[palabras[j]] = vector[palabras[j]] + 1; 
                    }
                }
            }

            foreach (KeyValuePair<string, int> kvp in vector)
            {
               // Console.WriteLine("palabra = {0}, incidendia = {1}", kvp.Key, kvp.Value);
                tamañoDiccionario++;
            }


            matrizincidencia = new int[arregloDeFrasesCortex.Length][];



            for (int i = 0; i < arregloDeFrasesCortex.Length; i++)
            {
                int indice = 0;

                matrizincidencia[i] = new int[tamañoDiccionario];
                
                
                foreach (KeyValuePair<string, int> kvp in vector)
                {

                    if (arregloDeFrasesCortex[i].Contains(kvp.Key))
                    {
                        
                        matrizincidencia[i][indice] = int.Parse(""+kvp.Value);
                        frecuenciaTotalpalabras += kvp.Value;

                    }
                    else
                    {
                        matrizincidencia[i][indice] = 0;
                    }
                    indice++;
                   
                }
             
            }

    
         /*   for (int i = 0; i < arregloDeFrasesCortex.Length; i++)
            {
                for (int j = 0; j < tamañoDiccionario; j++)
                {
                    Console.Write("["+i+","+j+"]= "+matrizincidencia[i][j] + " ");
                }
                Console.WriteLine(" ");
            }*/
            
        }


        public void calculosIndicesParaMetricasCortex()
        {
            p = new int[matrizincidencia[0].Length];
            rareza = new int[matrizincidencia[0].Length];
            

            int indice = 0;
            int var = 0;
            int var2 = 0;


            for (int i = 0; i < matrizincidencia[0].Length; i++)
            {
                for (int j = 0; j < matrizincidencia.Length; j++)
                {
                    var += matrizincidencia[j][i];

                    if (matrizincidencia[j][i] > 0)
                        var2 += 1;
                }

                p[indice] = var;
                rareza[indice] = var2;
                indice++;
                
                var = 0;
                var2 = 0;

            }


           /* Console.WriteLine("\n rareza ");

            for (int i = 0; i < indice; i++)
                Console.Write("[" + rareza[i]+"] ");

        */
        }

        public void entropiaCortex()
        {
            entropia = new float[matrizincidencia.Length];
            
            for (int i = 0; i < matrizincidencia.Length; i++)
            {
                for (int j = 0; j < matrizincidencia[0].Length; j++)
                {
                    if (matrizincidencia[i][j] > 0)
                    {
                        float valor = (float)(p[j]) / (float)(frecuenciaTotalpalabras);
                        //Console.Write(" p " + p[j] + " frecuencia " + frecuenciaTotalpalabras + "valor ");
                        entropia[i] += (float)(-valor) * (float)Math.Log(valor,2);
                        //Console.Write(" entropia ");
                        valor = 0;
                    }
                    else
                    {
                        entropia[i] += 0;
                    }

                    //Console.WriteLine();
                }

            }
/*
            Console.WriteLine("\n calculo entropia");
            for (int i = 0; i < matrizincidencia.Length; i++)
                Console.Write("["+entropia[i]+"] ");
            */
        }


        public void frecuenciaXrarezaCortex()
        {

       //     Console.WriteLine("\n frecuencia rareza");

            frecuenciaRareza = new float[matrizincidencia.Length];

            for (int i = 0; i < matrizincidencia.Length; i++)
            {
                for (int j = 0; j < matrizincidencia[0].Length; j++)
                {
                    if (matrizincidencia[i][j] > 0)
                    {
                        int valor = rareza[j] * matrizincidencia[i][j];
                        //Console.Write(" p " + p[j] + " frecuencia " + frecuenciaTotalpalabras + "valor ");
                        frecuenciaRareza[i] += valor;
                        //Console.Write(" entropia ");
                        valor = 0;
                    }
                    else
                    {
                        frecuenciaRareza[i] += 0;
                    }
                    //Console.WriteLine();
                }
               // Console.Write("["+frecuenciaRareza[i]+"] ");
            }



        }

        public void normalizacionMetricas()
        {
            float minEntropia = entropia.Min();
            float maxEntropia = entropia.Max();

            float minRareza = frecuenciaRareza.Min();
            float maxRareza = frecuenciaRareza.Max();



           // Console.WriteLine("\n entropia: min" + minEntropia + " max " + maxEntropia);

            for (int i = 0; i < entropia.Length; i++)
            {
                entropia[i] = Math.Abs((entropia[i] - minEntropia) / (maxEntropia - minEntropia));
            }

            /*
            Console.WriteLine("\n nuevo calculo entropia");
            for (int i = 0; i < matrizincidencia.Length; i++)
                Console.Write("[" + entropia[i] + "] ");
            */


           // Console.WriteLine("\n rareza: min" + minRareza + " max " + maxRareza);

            for (int i = 0; i < frecuenciaRareza.Length; i++)
            {
                frecuenciaRareza[i] = Math.Abs((frecuenciaRareza[i] - minRareza) / (maxRareza - minRareza));
            }
            /*
            Console.WriteLine("\n nuevo calculo frecuencia rareza");
            for (int i = 0; i < matrizincidencia.Length; i++)
                Console.Write("[" + frecuenciaRareza[i] + "] ");
            */

        }


        public void algoritmoDecision()
        {

            float sumatoriaPositivaEntropia = 0;
            float sumatoriaNegativaEntropia = 0;

            float sumatoriaPositivaFrecuencia = 0;
            float sumatoriaNegativaFrecuencia = 0;

            votoEntropia = 0;
            votoFrecuencia = 0;

            for (int i = 0; i < matrizincidencia.Length; i++)
            {
                if (entropia[i] > 0.5)
                {
                    sumatoriaPositivaEntropia += (float)(Math.Abs(entropia[i]) - 0.5);
                }
                else
                    if (entropia[i] < 0.5)
                    {
                        sumatoriaNegativaEntropia += (float)(0.5 - Math.Abs(entropia[i]));
                    }


                if (frecuenciaRareza[i] > 0.5)
                {
                    sumatoriaPositivaFrecuencia += (float)(Math.Abs(frecuenciaRareza[i] - 0.5));
                }
                else
                    if (frecuenciaRareza[i] < 0.5)
                    {
                        sumatoriaNegativaFrecuencia += (float)(0.5 - Math.Abs(frecuenciaRareza[i]));
                    }
            
            }


            if (sumatoriaPositivaEntropia > sumatoriaNegativaEntropia)
            {
                votoEntropia = (float)0.5 + (float)(sumatoriaPositivaEntropia / matrizincidencia.Length);
            }
            else
            {
                votoEntropia = (float)0.5 - (float)(sumatoriaNegativaEntropia / matrizincidencia.Length);
            }


            if (sumatoriaPositivaFrecuencia > sumatoriaNegativaFrecuencia)
            {
                votoFrecuencia = (float)0.5 + (float)(sumatoriaPositivaFrecuencia / matrizincidencia.Length);
            }
            else
            {
                votoFrecuencia = (float)0.5 - (float)(sumatoriaNegativaFrecuencia / matrizincidencia.Length);
            }


          //  Console.WriteLine("\nsumas entropia: positivos " + sumatoriaPositivaEntropia + " negativo " + sumatoriaNegativaEntropia);
          //  Console.WriteLine("sumas frecuencias: positivos " + sumatoriaPositivaFrecuencia + " negativo " + sumatoriaNegativaFrecuencia);
          //  Console.WriteLine("voto entropia " + votoEntropia + " voto frecuencia " + votoFrecuencia);


            if (votoEntropia >= votoFrecuencia)
            {
                getArregloFrasesOriginalOrdenadasImportancia(entropia);
            }
            else
            {
                getArregloFrasesOriginalOrdenadasImportancia(frecuenciaRareza);
            }



            this.matrizincidencia = null;

        }

        public float[] getFrecuencia()
        {
           return frecuenciaRareza;
        }

        public float[] getEntropia()
        {
             return entropia;
        }

        public float getVotoFrecuencia()
        {
            return votoFrecuencia*100;
        }

        public float getVotoEntropia()
        {
            return votoEntropia * 100;
        }

        public String[] getArregloFrasesCortex()
        {
            return arregloDeFrasesCortex;
        }


        public String[] getArregloFrasesOriginal()
        {
            return arregloDeFrasesOriginal;
        }

        public int[] getIndiceFrasesOriginal()
        {
            return indiceTabla;
        }

        public void getArregloFrasesOriginalOrdenadasImportancia(float [] lista)
        {

            indiceTabla = new int[lista.Length];

            for (int i = 0; i < lista.Length; i++)
                indiceTabla[i] = i;
            
            
            int salto = 0;
            int sw = 0;
            
            float auxi = 0;
            int auxi2 = 0;
            String auxi3 = "";
            String auxi4 = "";

            float auxi5 = 0;
            float auxi6 = 0;

            int e = 0;
            salto = lista.Length / 2;
            while (salto > 0)
            {
                sw = 1;
                while (sw != 0)
                {
                    sw = 0;
                    e = 1;
                    while (e <= (lista.Length - salto))
                    {
                        if (lista[e - 1] < lista[(e - 1) + salto])
                        {
                            auxi = lista[(e - 1) + salto];
                            
                            lista[(e - 1) + salto] = lista[e - 1];
                            lista[(e - 1)] = auxi;
                            sw = 1;


                            
                            auxi2 = indiceTabla[(e - 1) + salto];
                            indiceTabla[(e - 1) + salto] = indiceTabla[e - 1];
                            indiceTabla[(e - 1)] = auxi2;


                            auxi3 = arregloDeFrasesOriginal[(e - 1) + salto];
                            arregloDeFrasesOriginal[(e - 1) + salto] = arregloDeFrasesOriginal[e - 1];
                            arregloDeFrasesOriginal[(e - 1)] = auxi3;

                            
                            auxi4 = arregloDeFrasesCortex[(e - 1) + salto];
                            arregloDeFrasesCortex[(e - 1) + salto] = arregloDeFrasesCortex[e - 1];
                            arregloDeFrasesCortex[(e - 1)] = auxi4;
                            //Console.WriteLine("Ordenando cortex " + auxi4);
                            
                            /*
                            auxi5 = entropia[(e - 1) + salto];
                            entropia[(e - 1) + salto] = entropia[e - 1];
                            entropia[(e - 1)] = auxi5;
                            //Console.WriteLine("Ordenando cortex " + auxi5);

                            
                            auxi6 = frecuenciaRareza[(e - 1) + salto];
                            frecuenciaRareza[(e - 1) + salto] = frecuenciaRareza[e - 1];
                            frecuenciaRareza[(e - 1)] = auxi6;
                            //Console.WriteLine("Ordenando cortex " + auxi5);
                           */
                        }
                        e++;
                    }
                }
                salto = salto / 2;
            }

           /* Console.WriteLine("Vector ordenados en forma descendente");
            for (int f = 0; f < lista.Length; f++)
            {
                Console.Write("\n indice " + indiceTabla[f] + " peso " + lista[f] + " " + " F.O " + arregloDeFrasesOriginal[f] + " F.C " + arregloDeFrasesCortex[f]);
            }*/
            
        }
        


    }
}
